// ------------------------------------------------------------------------
// 版权信息
// 版权归重庆虫儿飞科技有限公司所有。
// 所有权利保留。
// 官方网站：https://netokit.com
// 许可证信息
// Neto.Kit 项目主要遵循 MIT 许可证和 Apache 许可证（版本 2.0）进行分发和使用。
// 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。
// 
// 使用条款
// 使用本代码应遵守相关法律法规和许可证的要求。
// 
// 免责声明
// 对于因使用本代码而产生的任何直接、间接、偶然、特殊或后果性损害，我们不承担任何责任。
// 
// 其他重要信息
// Neto.Kit 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。
// 有关 Neto.Kit 项目的其他详细信息，请参阅位于源代码树根目录中的 COPYRIGHT 和 DISCLAIMER 文件。
// 
// 更多信息
// 请访问 https://netokit.com 获取更多关于 Neto.Kit 项目的许可证和版权信息。
// ------------------------------------------------------------------------

#region

using Neto.Core.CommonDto.Api;
using Neto.Db.SqlSugar;
using Neto.Db.SqlSugar.Paged;
using Yitter.IdGenerator;

#endregion

namespace Neto.Application;

/// <summary>
///     角色服务
/// </summary>
/// <param name="db"></param>
[ApiDescriptionSettings("Api", Name = "ApiRoleService")]
[ApiArea()]
[PgApiController("角色服务", area: "Api", MenuPCode = "Sys_Manage")]
[PgApiMenu("角色管理", "manage_role", MenuPCode = "Sys_Manage", Icon = "carbon:user-role", Sort = 2)]
public class ApiRoleService(
    ISqlSugarClient db)
    : IDynamicApiController
{
    /// <summary>
    ///     获取角色菜单权限
    /// </summary>
    /// <returns></returns>
    [HttpPost]
    [OperationId(nameof(GetRoleMenuRight))]
    [PgApiAction("获取角色菜单权限", Action = "GetRoleMenuRight", Sort = 1)]
    public async Task<List<long>> GetRoleMenuRight(long roleId)
    {
        var result = await db.Queryable<SysRoleMenu>().Where(it => it.RoleId == roleId)
            .Select(it => it.MenuId)
            .ToListAsync();

        return result;
    }

    /// <summary>
    ///     设置角色菜单权限
    /// </summary>
    /// <returns></returns>
    [HttpPost]
    [OperationId(nameof(SetRoleMenuRight))]
    [PgApiAction("设置角色菜单权限", Action = "SetRoleMenuRight", Sort = 2)]
    public async Task<bool> SetRoleMenuRight(ApiRoleMenuInput input)
    {
        try
        {
            await db.Ado.BeginTranAsync();

            //查询这个用户现在有哪些菜单权限
            var dbRoleMenuIds = await db.Queryable<SysMenu>()
                .InnerJoin<SysRoleMenu>((sm, srm) => sm.Id == srm.MenuId)
                .Where((sm, srm) => sm.PgType == input.PgType)
                .Where((sm, srm) => srm.RoleId == input.RoleId)
                .Select((sm, srm) => srm.MenuId)
                .ToListAsync();

            // 验证输入菜单ID的有效性（关键！防止插入无效菜单）
            var validMenuIds = await db.Queryable<SysMenu>()
                .Where(sm => sm.PgType == input.PgType)
                .Where(sm => input.MenuIds.Contains(sm.Id))
                .Select(sm => sm.Id)
                .ToListAsync();

            //获取哪些菜单Id应该被删除(修改前应有,修改后没有)
            var deleteRoleMenuIds = dbRoleMenuIds.Except(validMenuIds).ToList();

            //获取应该新增哪些菜单Id(修改前没有,修改有应有)
            var insertRoleMenuIds = validMenuIds.Except(dbRoleMenuIds).ToList();


            if (deleteRoleMenuIds.Count > 0)
                //删除之前的权限
                await db.Deleteable<SysRoleMenu>().Where(it => it.RoleId == input.RoleId)
                    .Where(it => deleteRoleMenuIds.Contains(it.MenuId))
                    .ExecuteCommandAsync();

            if (insertRoleMenuIds.Count > 0)
            {
                var insert = insertRoleMenuIds.Select(it => new SysRoleMenu
                {
                    Id = YitIdHelper.NextId(), RoleId = input.RoleId, MenuId = it
                }).ToList();
                await db.Insertable(insert).ExecuteCommandAsync();
            }

            if (input.PgType == PgType.Menu)
            {
                //检查用户表的首页是否修改了
                var roleEntity = await db.Queryable<SysRole>().Where(it => it.Id == input.RoleId).FirstAsync();
                if (roleEntity.HomeMenuId != input.HomeMenuId)
                {
                    roleEntity.HomeMenuId = input.HomeMenuId;
                    await db.Updateable(roleEntity).ExecuteCommandAsync();
                }
            }


            await db.Ado.CommitTranAsync();


            return true;
        }
        catch (Exception)
        {
            await db.Ado.RollbackTranAsync();
            return false;
        }
    }

    /// <summary>
    ///     获取角色列表
    /// </summary>
    /// <returns></returns>
    [HttpPost]
    [OperationId(nameof(GetPagedList))]
    [PgApiAction("获取角色列表", Action = "GetPagedList", Sort = 3)]
    public async Task<PagedList<ApiRoleOut>> GetPagedList(ApiRoleQuery query)
    {
        var queryable = db.Queryable<SysRole>();


        if (query.IsEnable.HasValue) queryable = queryable.Where(su => su.IsEnable == query.IsEnable);

        if (!string.IsNullOrWhiteSpace(query.KeyWords))
        {
            var kw = query.KeyWords?.Trim()?.ToLower() ?? "";
            if (kw.IsValidLong() || kw.IsValidInt32())
            {
                var tempId = Convert.ToInt64(kw);
                queryable = queryable.Where(su =>
                    su.Code.Contains(query.KeyWords) ||
                    su.Name.Contains(query.KeyWords) ||
                    su.Id == tempId
                );
            }
            else
                queryable = queryable.Where(su =>
                    su.Code.Contains(query.KeyWords) ||
                    su.Name.Contains(query.KeyWords)
                );
        }

        if (query.StartTime.HasValue) queryable = queryable.Where(it => it.CreationTime >= query.StartTime.Value);
        if (query.EndTime.HasValue) queryable = queryable.Where(it => it.CreationTime <= query.EndTime.Value);
        var list = await queryable
            .OrderBy(su => su.Sort)
            .Select(su => new ApiRoleOut
            {
                //自动映射
            }, true)
            .ToPagedListAsync(query.PageIndex, query.PageSize);


        return list;
    }

    /// <summary>
    ///     添加或者修改
    /// </summary>
    /// <returns></returns>
    [HttpPost]
    [OperationId(nameof(InsertOrUpdate))]
    [PgApiAction("添加或者修改", Action = "GetRoleMenuRight", Sort = 4)]
    public async Task<long> InsertOrUpdate(ApiRoleInput input)
    {
        //var roleids = input.RoleIds.ToLongList();
        if (input.Id > 0)
        {
            #region 修改

            if (db.Queryable<SysRole>().Any(o => o.Id != input.Id && o.Code == input.Code))
                throw Oops.Bah($"角色代码：{input.Code}已存在");

            if (db.Queryable<SysRole>().Any(o => o.Id != input.Id && o.Name == input.Name))
                throw Oops.Bah($"角色名称：{input.Name}已存在");

            var dbentity = await db.Queryable<SysRole>().FirstAsync(o => o.Id == input.Id);
            input.Adapt(dbentity);
            await db.UpdateAsync(dbentity);

            #endregion 修改
        }
        else
        {
            #region 新增

            if (db.Queryable<SysRole>().Any(o => o.Code == input.Code))
                throw Oops.Bah($"角色代码：{input.Code}已存在");

            if (db.Queryable<SysRole>().Any(o => o.Name == input.Name))
                throw Oops.Bah($"角色名称：{input.Name}已存在");

            var addentity = input.Adapt<SysRole>();

            var roleId = await db.InsertRsIdAsync(addentity);

            input.Id = roleId;

            #endregion 新增
        }


        await SetRolePermission(input);
        return input.Id.Value;
    }

    /// <summary>
    ///     设置角色权限
    /// </summary>
    /// <param name="input">输入role对象</param>
    /// <returns></returns>
    private async Task SetRolePermission(ApiRoleInput input)
    {
        //获取全部菜单数据
        var dbmenus = await db.Queryable<SysMenu>().ToListAsync();
        var permissions = input.ActionIds;

        #region 从数据库移除删除的权限

        {
            //删除这个角色的所有菜单。。。
            await db.Deleteable<SysRoleMenu>(o => o.RoleId == input.Id).ExecuteCommandAsync();
        }

        #endregion 从数据库移除删除的权限

        #region 新增权限

        //查询这些action包括了哪些菜单
        if (input.ActionIds.Count == 0) return;

        //var controllerCode = await db.Queryable<SysMenu>().Where(it => input.ActionIds.Contains(it.Id))
        //     .Select(it => it.ControllerCode)
        //     .Distinct()
        //     .ToListAsync();
        ////查询这些控制器下有哪些菜单
        //var menuIds = await db.Queryable<SysMenu>()
        //    .Where(it => it.PgType == PgType.Menu && controllerCode.Contains(it.ControllerCode))
        //    .Select(it => it.Id)
        //    .ToListAsync();


        var menuIds = await db.Queryable<SysMenu>()
            .Where(it => it.PgType == PgType.Menu)
            .Where(it => SqlFunc.Subqueryable<SysMenu>()
                .Where(s => input.ActionIds.Contains(s.Id) && s.ControllerCode == it.ControllerCode)
                .Any())
            .Select(it => it.Id)
            .ToListAsync();


        //执行添加权限
        List<SysRoleMenu> insert =
        [
            ..input.ActionIds.Select(it => new SysRoleMenu
            {
                Id = YitIdHelper.NextId(), RoleId = input.Id.Value, MenuId = it
            }),
            ..menuIds.Select(it => new SysRoleMenu { Id = YitIdHelper.NextId(), RoleId = input.Id.Value, MenuId = it })
        ];
        await db.Insertable(insert).ExecuteCommandAsync();

        #endregion 新增权限
    }


    /// <summary>
    ///     删除角色
    /// </summary>
    /// <returns></returns>
    [HttpPost]
    [OperationId(nameof(BatchDelete))]
    [PgApiAction("删除角色", Action = "BatchDelete", Sort = 5)]
    public async Task<bool> BatchDelete(List<long> ids)
    {
        try
        {
            await db.Ado.BeginTranAsync();
            await db.FakeDeleteAsync<SysRole>(w => ids.Contains(w.Id));
            await db.Ado.CommitTranAsync();
            return true;
        }
        catch (Exception)
        {
            await db.Ado.RollbackTranAsync();

            return false;
        }
    }

    /// <summary>
    ///     设置状态
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpPost]
    [OperationId(nameof(SetState))]
    [PgApiAction("设置状态", Action = "SetState", Sort = 6)]
    public async Task<bool> SetState(ApiStateInput input)
    {
        var result = await db.SetStateByIdAsync<SysRole>(input.Id, input.State, input.Field);


        return result;
    }


    /// <summary>
    ///     获取角色
    /// </summary>
    /// <returns></returns>
    [HttpPost]
    [OperationId(nameof(GetAll))]
    [PgApiAction("获取角色", Action = "GetAll", Sort = 7)]
    public async Task<List<ApiRoleOut>> GetAll()
    {
        var list = await db.Queryable<SysRole>().Select(s => new ApiRoleOut { Id = s.Id.SelectAll() }, true)
            .ToListAsync();


        return list;
    }


    /// <summary>
    ///     获取用户角色Id
    /// </summary>
    /// <returns></returns>
    [HttpPost]
    [OperationId(nameof(GetUserRoleIds))]
    [PgApiAction("获取用户角色Id", Action = "GetUserRoleIds", Sort = 8)]
    public async Task<List<long>> GetUserRoleIds(long userId)
    {
        var result = await db.Queryable<SysUserRole>().Where(it => it.UserId == userId)
            .Select(it => it.RoleId)
            .ToListAsync();


        return result;
    }
}